//  
//  File Name   :	MathCommon.cpp
//  Description :	MathCommon implementation file.
//  Author      :	William McVicar
//  Mail        :	mcvicar.william@gmail.com
//  
//  Design Patterns :
//  

// Precompiled Header
#include "CommonDefines.h"

//  Library Includes

//  Local Includes

//  This Includes
#include "MathCommon.h"

//  Static Variables

//  Static Function Prototypes

//  Implementation

namespace Protein
{

template<> const float Math<float>::EPSILON = FLT_EPSILON;
template<> const float Math<float>::ZERO_TOLERANCE = 1e-06f;
template<> const float Math<float>::MAX_REAL = FLT_MAX;
template<> const float Math<float>::PI =(float)(4.0*atan(1.0));
template<> const float Math<float>::TWO_PI = 2.0f*Math<float>::PI;
template<> const float Math<float>::HALF_PI = 0.5f*Math<float>::PI;
template<> const float Math<float>::INV_PI = 1.0f/Math<float>::PI;
template<> const float Math<float>::INV_TWO_PI = 1.0f/Math<float>::TWO_PI;
template<> const float Math<float>::DEG_TO_RAD = Math<float>::PI/180.0f;
template<> const float Math<float>::RAD_TO_DEG = 180.0f/Math<float>::PI;
template<> const float Math<float>::LN_2 = Math<float>::Log(2.0f);
template<> const float Math<float>::LN_10 = Math<float>::Log(10.0f);
template<> const float Math<float>::INV_LN_2 = 1.0f/Math<float>::LN_2;
template<> const float Math<float>::INV_LN_10 = 1.0f/Math<float>::LN_10;

template<> const double Math<double>::EPSILON = DBL_EPSILON;
template<> const double Math<double>::ZERO_TOLERANCE = 1e-08;
template<> const double Math<double>::MAX_REAL = DBL_MAX;
template<> const double Math<double>::PI = 4.0*atan(1.0);
template<> const double Math<double>::TWO_PI = 2.0*Math<double>::PI;
template<> const double Math<double>::HALF_PI = 0.5*Math<double>::PI;
template<> const double Math<double>::INV_PI = 1.0/Math<double>::PI;
template<> const double Math<double>::INV_TWO_PI = 1.0/Math<double>::TWO_PI;
template<> const double Math<double>::DEG_TO_RAD = Math<double>::PI/180.0;
template<> const double Math<double>::RAD_TO_DEG = 180.0/Math<double>::PI;
template<> const double Math<double>::LN_2 = Math<double>::Log(2.0);
template<> const double Math<double>::LN_10 = Math<double>::Log(10.0);
template<> const double Math<double>::INV_LN_2 = 1.0/Math<double>::LN_2;
template<> const double Math<double>::INV_LN_10 = 1.0/Math<double>::LN_10;

template <>
float Math<float>::InvSqrt( float _fValue )
{
    float fHalf = 0.5f*_fValue;
    int i  = *(int*)&_fValue;
	i = INV_SQRT_YNOUGHT_GUESS - (i >> 1);
    _fValue = *(float*)&i;
    _fValue = _fValue*(1.5f - fHalf*_fValue*_fValue);
    return _fValue;
}

template <>
double Math<double>::InvSqrt( double _dValue )
{
    double dHalf = 0.5*_dValue;
    i64 i  = *(i64*)&_dValue;

    i = 0x5fe6ec85e7de30daLL - (i >> 1);

    _dValue = *(double*)&i;
    _dValue = _dValue*(1.5 - dHalf*_dValue*_dValue);
    return _dValue;
}

template<> float
Math<float>::FlipSign( float _f )
{
	int i = *reinterpret_cast<const int*>( &_f );

	i ^= SIGN_BIT_FLOAT;

	_f = *reinterpret_cast<const float*>( &i );
	return _f;
}

template<> double
Math<double>::FlipSign( double _d )
{
	i64 i = *reinterpret_cast<i64*>( &_d );

	i ^= SIGN_BIT_DOUBLE;

	_d = *reinterpret_cast<const double*>( &i );
	return _d;
}

template<> void 
Math<float>::FlipSignVoid ( float &_fValue )
{
	int i = *reinterpret_cast<const int*>( &_fValue );

	i ^= SIGN_BIT_FLOAT;

	_fValue = *reinterpret_cast<const float*>( &i );
}

template<> void 
Math<double>::FlipSignVoid( double &_dValue )
{
	i64 i = *reinterpret_cast<const i64*>( &_dValue );

	i ^= SIGN_BIT_DOUBLE;

	_dValue = *reinterpret_cast<const double*>( &i );
}

}